home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / monster.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  35KB  |  1,209 lines

  1. /*
  2.  * static char *rcsid_monster_c =
  3.  *    "$Id: monster.c,v 1.27 1996/06/10 06:48:25 master Exp $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #include <global.h>
  30. #ifndef __CEXTRACT__
  31. #include <sproto.h>
  32. #endif
  33.  
  34. extern spell spells[NROFREALSPELLS];
  35.  
  36. object *get_enemy(object *npc) {
  37.   if ((npc->move_type & HI4) == 16)
  38.     if (npc->owner != NULL)
  39.       return npc->enemy = npc->owner->enemy;
  40.     else npc->enemy = NULL;
  41.   if(npc->enemy) {
  42.     if(QUERY_FLAG(npc->enemy,FLAG_REMOVED)||QUERY_FLAG(npc->enemy,FLAG_FREED)
  43.        ||!(RANDOM()%20)||
  44.        (npc->enemy->type!=PLAYER&&npc->enemy->type!=GOLEM)||
  45.        (npc->enemy->type==PLAYER&&npc->enemy->contr->state)||
  46.        npc->enemy->map!=npc->map)
  47.       npc->enemy=NULL;
  48.   }
  49.   return npc->enemy;
  50. }
  51.  
  52. object *find_enemy(object *npc) {
  53.   object *tmp;
  54.   if ((npc->move_type & HI4) == PETMOVE)
  55.     return get_pet_enemy(npc);
  56.   if((tmp=get_enemy(npc))!=NULL)
  57.     return tmp;
  58.   if(QUERY_FLAG(npc, FLAG_UNAGGRESSIVE))
  59.     return NULL;
  60.   tmp = get_nearest_player(npc);
  61.   if(QUERY_FLAG(npc, FLAG_FRIENDLY)) {
  62.     object *op;
  63.     if(tmp == NULL)
  64.       return NULL;
  65.     if((op = get_enemy(tmp))!=NULL)
  66.       return op;
  67.     return NULL;
  68.   }
  69.   return tmp;
  70. }
  71.  
  72. #define MIN_MON_RADIUS 3 /* minimum monster detection radius */ 
  73.  
  74. int check_wakeup(object *op, object *enemy) {
  75.   int radius = op->stats.Wis>MIN_MON_RADIUS?op->stats.Wis:MIN_MON_RADIUS;
  76.   objectlink *ol;
  77.  
  78.   /* blinded monsters can only find nearby objects to attack */
  79.   if(QUERY_FLAG(op, FLAG_BLIND) && !QUERY_FLAG(op, FLAG_SEE_INVISIBLE)) 
  80.     radius = MIN_MON_RADIUS;
  81. #ifdef USE_LIGHTING 
  82.   /* This covers the situation where the monster is in the dark 
  83.    * and has an enemy. If the enemy has no carried light (or isnt 
  84.    * glowing!) then the monster has trouble finding the enemy. 
  85.    * Remember we already checked to see if the monster can see in 
  86.    * the dark. */
  87.   else if(op->map&&op->map->darkness>0&&enemy&&!has_carried_lights(enemy))
  88.   {
  89.       int dark = radius/(op->map->darkness);
  90.       radius = (dark>MIN_MON_RADIUS)?(dark+1):MIN_MON_RADIUS;
  91.   } 
  92. #endif
  93.   else if(!QUERY_FLAG(op,FLAG_SLEEP)) return 1;
  94.  
  95.   for(ol=first_friendly_object;ol!=NULL;ol=ol->next)
  96.     if(ol->ob->map==op->map&&
  97.        (QUERY_FLAG(ol->ob,FLAG_STEALTH)?(abs(ol->ob->x-op->x)<radius/2+1 &&
  98.                          abs(ol->ob->y-op->y)<radius/2+1):
  99.                         (abs(ol->ob->x-op->x)<radius&&
  100.                          abs(ol->ob->y-op->y)<radius)))
  101.     {
  102.       CLEAR_FLAG(op,FLAG_SLEEP);
  103.       return 1;
  104.     }
  105.   return 0;
  106. }
  107.  
  108. int move_randomly(object *op) {
  109.   int i;
  110.  
  111.   for(i=0;i<15;i++);
  112.     if(move_object(op,RANDOM()%8+1))
  113.       return 1;
  114.   return 0;
  115. }
  116.  
  117. /*
  118.  * Move-monster returns 1 if the object has been freed, otherwise 0.
  119.  */
  120.  
  121. int move_monster(object *op) {
  122.   int dir,diff;
  123.   object *part, *owner, *enemy = find_enemy(op);
  124.  
  125.  
  126.   if(QUERY_FLAG(op, FLAG_SLEEP)||QUERY_FLAG(op, FLAG_BLIND)
  127. #ifdef USE_LIGHTING  
  128.     ||((op->map->darkness>0)&&!QUERY_FLAG(op,FLAG_SEE_IN_DARK)
  129.     &&!QUERY_FLAG(op,FLAG_SEE_INVISIBLE))
  130. #endif
  131.   ) {
  132.     if(!check_wakeup(op,enemy))
  133.       return 0;
  134.   }
  135.  
  136.   if(op->pick_up)
  137.     monster_check_pickup(op);
  138.  
  139.   if(op->will_apply)
  140.     monster_apply_below(op); /* Check for items to apply below */
  141.  
  142.   if(op->stats.Con&&op->stats.hp<op->stats.maxhp) {
  143.     op->stats.hp+=op->stats.Con;
  144.     if (QUERY_FLAG(op,FLAG_RUN_AWAY) &&
  145.         op->stats.hp >= (signed short)(((float)op->run_away/(float)100)*
  146.                         (float)op->stats.maxhp))
  147.       CLEAR_FLAG(op, FLAG_RUN_AWAY);
  148.     if(op->stats.hp>op->stats.maxhp)
  149.       op->stats.hp=op->stats.maxhp;
  150.   }
  151.   if(QUERY_FLAG(op, FLAG_SCARED)&&!(RANDOM()%20))
  152.     CLEAR_FLAG(op,FLAG_SCARED); /* Time to regain some "guts"... */
  153.  
  154.   if(!enemy) {
  155.     if(QUERY_FLAG(op, FLAG_ONLY_ATTACK)) {
  156.       remove_ob(op);
  157.       free_object(op);
  158.       return 1;
  159.     }
  160.     if (op->move_type & HI4) {
  161.       switch (op->move_type & HI4) {
  162.         case (PETMOVE):
  163.           pet_move (op);
  164.           if(QUERY_FLAG(op, FLAG_REMOVED)) {
  165.             remove_friendly_object(op);
  166.             free_object(op);
  167.             return 1;
  168.           }
  169.           break;
  170.         case (CIRCLE1):
  171.           circ1_move (op);
  172.           break;
  173.         case (CIRCLE2):
  174.           circ2_move (op);
  175.           break;
  176.         case (PACEV):
  177.           pace_movev(op);
  178.           break;
  179.         case (PACEH):
  180.           pace_moveh(op);
  181.           break;
  182.         case (PACEV2):
  183.           pace2_movev (op);
  184.           break;
  185.         case (PACEH2):
  186.           pace2_moveh (op);
  187.           break;
  188.         case (RANDO):
  189.           rand_move (op);
  190.           break;
  191.         case (RANDO2):
  192.           move_randomly (op);
  193.           break;
  194.       }
  195.       if(QUERY_FLAG(op, FLAG_FREED))
  196.         return 1;
  197.       return 0;
  198.     }
  199.     if (QUERY_FLAG(op,FLAG_RANDOM_MOVE))
  200.       (void) move_randomly(op);
  201.     return 0;
  202.   }
  203.   /* There is something to attack */
  204.  
  205.   if((op->type&HI4) == PETMOVE && (owner = get_owner(op)) != NULL &&
  206.      op->map != owner->map)
  207.   {
  208.     follow_owner(op, owner);
  209.     if(QUERY_FLAG(op, FLAG_REMOVED) && FABS(op->speed) > 0.00001) {
  210.       remove_friendly_object(op);
  211.       free_object(op);
  212.       return 1;
  213.     }
  214.     return 0;
  215.   }
  216.    
  217.   /* doppleganger code to change monster facing to that of the nearest 
  218.      player */
  219.   if( (op->race != NULL)&& strcmp(op->race,"doppleganger") == 0){
  220.     op->face = enemy->face; 
  221.     strcpy(op->name,enemy->name);
  222.   }
  223.  
  224.   part = get_nearest_part(op,enemy);
  225.  
  226.   dir=find_dir_2(part->x-enemy->x,part->y-enemy->y);
  227.   if(QUERY_FLAG(op,FLAG_IS_TURNING))
  228.     op->value=(enemy->x>op->x);
  229.  
  230.   if(QUERY_FLAG(op, FLAG_SCARED) || QUERY_FLAG(op,FLAG_RUN_AWAY))
  231.     dir=absdir(dir+4);
  232.  
  233.   if(QUERY_FLAG(op,FLAG_CONFUSED))
  234.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  235.  
  236.   if (!QUERY_FLAG(op, FLAG_SCARED)) {
  237.     if(QUERY_FLAG(op,FLAG_CAST_SPELL))
  238.       if(monster_cast_spell(op,part,enemy,dir))
  239.         return 0;
  240.     if(QUERY_FLAG(op,FLAG_READY_WAND)&&!(RANDOM()%3))
  241.       if(monster_use_wand(op,part,enemy,dir))
  242.         return 0;
  243.     if(QUERY_FLAG(op,FLAG_READY_ROD)&&!(RANDOM()%4))
  244.       if(monster_use_rod(op,part,enemy,dir))
  245.         return 0;
  246.     if(QUERY_FLAG(op,FLAG_READY_HORN)&&!(RANDOM()%5))
  247.       if(monster_use_horn(op,part,enemy,dir))
  248.         return 0;
  249. #ifdef ALLOW_SKILLS
  250.     if(QUERY_FLAG(op,FLAG_READY_SKILL)&&!(RANDOM()%3))
  251.       if(monster_use_skill(op,part,enemy,dir))
  252.     return 0;
  253. #endif
  254.     if(QUERY_FLAG(op,FLAG_READY_BOW)&&!(RANDOM()%2))
  255.       if(monster_use_bow(op,part,enemy,dir))
  256.         return 0;
  257.   }
  258.   if ((op->move_type & LO4) && !QUERY_FLAG(op, FLAG_SCARED)) {
  259.      switch (op->move_type & LO4) {
  260.      case DISTATT:
  261.        dir = dist_att (dir,op,enemy,part);
  262.        break;
  263.      case RUNATT:
  264.        dir = run_att (dir,op,enemy,part);
  265.        break;
  266.      case HITRUN:
  267.        dir = hitrun_att(dir,op,enemy);
  268.        break;
  269.      case WAITATT:
  270.        dir = wait_att (dir,op,enemy,part);
  271.        break;
  272.      case RUSH:
  273.      case ALLRUN:
  274.        break; 
  275.      case DISTHIT:
  276.        dir = disthit_att (dir,op,enemy,part);
  277.        break;
  278.      case WAIT2:
  279.        dir = wait_att2 (dir,op,enemy,part);
  280.        break;
  281.      default:
  282.        LOG(llevDebug,"Illegal low mon-move: %d\n",op->move_type & LO4);
  283.      }
  284.    } 
  285.    if (!dir)
  286.      return (0);
  287.   if (!QUERY_FLAG(op,FLAG_STAND_STILL))
  288.   {
  289.     if(move_object(op,dir)) /* Can the monster move directly toward player? */
  290.       return 0;
  291.     if(QUERY_FLAG(op, FLAG_SCARED) || !can_hit(part,enemy) || QUERY_FLAG(op,FLAG_RUN_AWAY))
  292.     {                                    /* Try move around corners if !close */
  293.       int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM()&1) ? 1 : 2;
  294.       for(diff = 1; diff <= maxdiff; diff++)
  295.       {                                  /* try different detours */
  296.         int m = 1-(RANDOM()&2);          /* Try left or right first? */
  297.         if(move_object(op,absdir(dir + diff*m)) ||
  298.            move_object(op,absdir(dir - diff*m)))
  299.           return 0;
  300.       }
  301.     }
  302.   }
  303.  
  304. /*
  305.  * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
  306.  * direction if they can't move away.
  307.  */
  308.  
  309.   if (!QUERY_FLAG(op, FLAG_ONLY_ATTACK)&&(QUERY_FLAG(op,FLAG_RUN_AWAY)||QUERY_FLAG(op, FLAG_SCARED)))
  310.     if(move_randomly(op))
  311.       return 0;
  312.  
  313. /*
  314.  * Monster can't move...now see if it can hit the player...
  315.  *    Eneq(@csd.uu.se): Added check to handle RUN_AWAY and berzerk attack from
  316.  *    RUN_AWAY, locked in monster.
  317.  */
  318.   if (!QUERY_FLAG(op, FLAG_FRIENDLY) && enemy == op->enemy) {
  319.     object *nearest_player = get_nearest_player(op);
  320.     if (nearest_player && nearest_player != enemy && !can_hit(part,enemy)) {
  321.       op->enemy = NULL;
  322.       enemy = nearest_player;
  323.     }
  324.   }
  325.  
  326.   if(!QUERY_FLAG(op, FLAG_SCARED)&&can_hit(part,enemy))
  327.   {
  328.     if(QUERY_FLAG(op,FLAG_RUN_AWAY))
  329.     {
  330.       signed char tmp = (signed char)((float)part->stats.wc*(float)2);
  331.       part->stats.wc+=tmp;
  332. #ifdef ALLOW_SKILLS
  333.       (void)skill_attack(enemy,part,0,NULL);
  334. #else
  335.       (void)attack_ob(enemy,part);
  336. #endif
  337.       part->stats.wc-=tmp;
  338.     } else
  339. #ifdef ALLOW_SKILLS
  340.       (void)skill_attack(enemy,part,0,NULL);
  341. #else
  342.       (void) attack_ob(enemy,part);
  343. #endif
  344.   }
  345.   if(QUERY_FLAG(part,FLAG_FREED))    /* Might be freed by ghost-attack or hit-back */
  346.     return 1;
  347.   if(QUERY_FLAG(op, FLAG_ONLY_ATTACK)) {
  348.     remove_ob(op);
  349.     free_object(op);
  350.     return 1;
  351.   }
  352.   return 0;
  353. }
  354.  
  355. int can_hit(object *ob1,object *ob2) {
  356.   if(QUERY_FLAG(ob1,FLAG_CONFUSED)&&!(RANDOM()%3))
  357.     return 0;
  358.   return abs(ob1->x-ob2->x)<2&&abs(ob1->y-ob2->y)<2;
  359. }
  360.  
  361. /*Someday we may need this check */
  362. int can_apply(object *who,object *item) {
  363.   return 1;
  364. }
  365.  
  366. #define MAX_KNOWN_SPELLS 20
  367.  
  368. object *choose_random_spell(object *monster) {
  369.   object *altern[MAX_KNOWN_SPELLS];
  370.   object *tmp;
  371.   int i=0,j;
  372.  
  373.   for(tmp=monster->inv;tmp!=NULL;tmp=tmp->below)
  374.     if(tmp->type==ABILITY||tmp->type==SPELLBOOK) {
  375.       if(tmp->stats.maxsp)
  376.         for(j=0;i<MAX_KNOWN_SPELLS&&j<tmp->stats.maxsp;j++)
  377.           altern[i++]=tmp;
  378.       else
  379.         altern[i++]=tmp;
  380.       if(i==MAX_KNOWN_SPELLS)
  381.         break;
  382.     }
  383.   if(!i)
  384.     return NULL;
  385.   return altern[RANDOM()%i];
  386. }
  387.  
  388. int monster_cast_spell(object *head, object *part,object *pl,int dir) {
  389.   object *spell_item;
  390.   spell *sp;
  391.   int sp_typ, ability;
  392.   object *owner;
  393.  
  394.   if(head->stats.sp<head->stats.maxsp) /* Generate spell-points */
  395.     head->stats.sp+=head->stats.Pow;
  396.   if(!(RANDOM()%3)) /* Don't want to cast spells so often */
  397.     return 0;
  398.   if(!(dir=path_to_player(part,pl,0)))
  399.     return 0;
  400.   if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
  401.     int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
  402.     if(dirdiff(dir,dir2) < 2)
  403.       return 0; /* Might hit owner with spell */
  404.   }
  405.   if(QUERY_FLAG(head,FLAG_CONFUSED))
  406.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  407.   if((spell_item=choose_random_spell(head))==NULL) {
  408.     LOG(llevMonster,"Turned off spells in %s\n",head->name);
  409.     CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up books */
  410.     return 0;
  411.   }
  412.   if(spell_item->stats.hp) {
  413.     /* Alternate long-range spell: check how far away enemy is */
  414.     if(isqrt(distance(part,pl))>6)
  415.       sp_typ=spell_item->stats.hp;
  416.     else
  417.       sp_typ=spell_item->stats.sp;
  418.   } else
  419.     sp_typ=spell_item->stats.sp;
  420.   if((sp=find_spell(sp_typ))==NULL) {
  421.     LOG(llevError,"Warning: Couldn't find spell in item.\n");
  422.     return 0;
  423.   }
  424.   if (sp->onself) /* Spell should be cast on caster (ie, heal, strength) */
  425.     dir = 0;
  426.   if(head->stats.sp<sp->sp) /* Monster doesn't have enough spell-points */
  427.     return 0;
  428.   head->stats.sp-=sp->sp;
  429.   ability = (spell_item->type==ABILITY && !(spell_item->attacktype&AT_MAGIC));
  430.   return cast_spell(part,part,dir,sp_typ,ability, spellNormal,NULL);
  431. }
  432.  
  433. #ifdef ALLOW_SKILLS
  434. /* monster_use_skill()-implemented 95-04-28 to allow monster skill use.
  435.  * Note that monsters do not need the skills SK_MELEE_WEAPON and
  436.  * SK_MISSILE_WEAPON to make those respective attacks, if we 
  437.  * required that we would drastically increase the memory
  438.  * requirements of CF!! 
  439.  *
  440.  * The skills we are treating here are all but those. -b.t. 
  441.  */  
  442.  
  443. int monster_use_skill(object *head, object *part, object *pl,int dir) {
  444. object *skill, *owner;
  445.  
  446.   if(!(dir=path_to_player(part,pl,0)))
  447.     return 0;
  448.   if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
  449.     int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
  450.     if(dirdiff(dir,dir2) < 1)
  451.       return 0; /* Might hit owner with skill -thrown rocks for example ?*/
  452.   }
  453.   if(QUERY_FLAG(head,FLAG_CONFUSED))
  454.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  455.  
  456.   /* skill selection - monster will use the next unused skill.
  457.    * well...the following scenario will allow the monster to 
  458.    * toggle between 2 skills. One day it would be nice to make
  459.    * more skills available to monsters.  
  460.    */
  461.  
  462.   for(skill=head->inv;skill!=NULL;skill=skill->below)
  463.     if(skill->type==SKILL && skill!=head->chosen_skill) { 
  464.         head->chosen_skill=skill; 
  465.         break;
  466.     }
  467.  
  468.   if(!skill && !head->chosen_skill) {
  469.     LOG(llevDebug,"Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n",
  470.         head->name,head->count);
  471.     CLEAR_FLAG(head, FLAG_READY_SKILL);
  472.     return 0;
  473.   }
  474. /* use skill */
  475.   return do_skill(head,dir,NULL);
  476. }
  477.  
  478. #endif 
  479.  
  480. /* For the future: Move this function together with case 3: in fire() */
  481.  
  482. int monster_use_wand(object *head,object *part,object *pl,int dir) {
  483.   object *wand, *owner;
  484.   if(!(dir=path_to_player(part,pl,0)))
  485.     return 0;
  486.   if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
  487.     int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
  488.     if(dirdiff(dir,dir2) < 2)
  489.       return 0; /* Might hit owner with spell */
  490.   }
  491.   if(QUERY_FLAG(head,FLAG_CONFUSED))
  492.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  493.   for(wand=head->inv;wand!=NULL;wand=wand->below)
  494.     if(wand->type==WAND&&QUERY_FLAG(wand,FLAG_APPLIED))
  495.       break;
  496.   if(wand==NULL) {
  497.     LOG(llevError,"Error: Monster %s (%d) HAS_READY_WAND() without wand.\n",
  498.             head->name,head->count);
  499.     CLEAR_FLAG(head, FLAG_READY_WAND);
  500.     return 0;
  501.   }
  502.   if(wand->stats.food<=0) {
  503.     apply(head,wand);
  504.     CLEAR_FLAG(head, FLAG_READY_WAND);
  505.     if (wand->arch) {
  506.       CLEAR_FLAG(wand, FLAG_ANIMATE);
  507.       wand->face = wand->arch->clone.face;
  508.       wand->speed = 0;
  509.       update_ob_speed(wand);
  510.     }
  511.     return 0;
  512.   }
  513.   if(cast_spell(part,wand,dir,wand->stats.sp,0,spellWand,NULL)) {
  514.     wand->stats.food--;
  515.     return 1;
  516.   }
  517.   return 0;
  518. }
  519.  
  520. int monster_use_rod(object *head,object *part,object *pl,int dir) {
  521.   object *rod, *owner;
  522.   if(!(dir=path_to_player(part,pl,0)))
  523.     return 0;
  524.   if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
  525.     int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
  526.     if(dirdiff(dir,dir2) < 2)
  527.       return 0; /* Might hit owner with spell */
  528.   }
  529.   if(QUERY_FLAG(head,FLAG_CONFUSED))
  530.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  531.   for(rod=head->inv;rod!=NULL;rod=rod->below)
  532.     if(rod->type==ROD&&QUERY_FLAG(rod,FLAG_APPLIED))
  533.       break;
  534.   if(rod==NULL) {
  535.     LOG(llevError,"Error: Monster %s (%d) HAS_READY_ROD() without rod.\n",
  536.             head->name,head->count);
  537.     CLEAR_FLAG(head, FLAG_READY_ROD);
  538.     return 0;
  539.   }
  540.   if(rod->stats.hp<spells[rod->stats.sp].sp) {
  541.     return 0; /* Not recharged enough yet */
  542.   }
  543.   if(cast_spell(part,rod,dir,rod->stats.sp,0,spellRod,NULL)) {
  544.     drain_rod_charge(rod);
  545.     return 1;
  546.   }
  547.   return 0;
  548. }
  549.  
  550. int monster_use_horn(object *head,object *part,object *pl,int dir) {
  551.   object *horn, *owner;
  552.   if(!(dir=path_to_player(part,pl,0)))
  553.     return 0;
  554.   if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
  555.     int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
  556.     if(dirdiff(dir,dir2) < 2)
  557.       return 0; /* Might hit owner with spell */
  558.   }
  559.   if(QUERY_FLAG(head,FLAG_CONFUSED))
  560.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  561.   for(horn=head->inv;horn!=NULL;horn=horn->below)
  562.     if(horn->type==ROD&&QUERY_FLAG(horn,FLAG_APPLIED))
  563.       break;
  564.   if(horn==NULL) {
  565.     LOG(llevError,"Error: Monster %s (%d) HAS_READY_HORN() without horn.\n",
  566.             head->name,head->count);
  567.     CLEAR_FLAG(head, FLAG_READY_HORN);
  568.     return 0;
  569.   }
  570.   if(horn->stats.hp<spells[horn->stats.sp].sp) {
  571.     return 0; /* Not recharged enough yet */
  572.   }
  573.   if(cast_spell(part,horn,dir,horn->stats.sp,0,spellHorn,NULL)) {
  574.     drain_rod_charge(horn);
  575.     return 1;
  576.   }
  577.   return 0;
  578. }
  579.  
  580. int monster_use_bow(object *head, object *part, object *pl, int dir) {
  581.   object *bow, *arrow, *owner;
  582.   if(!(dir=path_to_player(part,pl,0)))
  583.     return 0;
  584.   if(QUERY_FLAG(head,FLAG_CONFUSED))
  585.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  586.   if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
  587.     int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
  588.     if(dirdiff(dir,dir2) < 1)
  589.       return 0; /* Might hit owner with spell */
  590.   }
  591.   for(bow=head->inv;bow!=NULL;bow=bow->below)
  592.     if(bow->type==BOW&&QUERY_FLAG(bow,FLAG_APPLIED))
  593.       break;
  594.   if(bow==NULL) {
  595.     LOG(llevError,"Error: Monster %s (%d) HAS_READY_BOW() without bow.\n",
  596.             head->name,head->count);
  597.     CLEAR_FLAG(head, FLAG_READY_BOW);
  598.     return 0;
  599.   }
  600.   if((arrow=find_arrow(head,bow->race)) == NULL) {
  601.     /* Out of arrows */
  602.     apply(head,bow);
  603.     CLEAR_FLAG(head, FLAG_READY_BOW);
  604.     return 0;
  605.   }
  606.   arrow=get_split_ob(arrow,1);
  607.   set_owner(arrow,head);
  608.   arrow->direction=dir;
  609.   arrow->x=part->x,arrow->y=part->y;
  610.   arrow->speed = 1;
  611.   update_ob_speed(arrow);
  612.   arrow->speed_left=0;
  613.   arrow->face=&new_faces[arrow->arch->faces[dir]];
  614.   arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
  615.   arrow->stats.hp = arrow->stats.dam; 
  616.   arrow->stats.dam+= (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : head->level)
  617.                      +bow->stats.dam+bow->magic+arrow->magic;
  618.   arrow->stats.wc= head->stats.wc - bow->magic - arrow->magic - 
  619.                    arrow->stats.wc;
  620.   arrow->map=head->map;
  621.   SET_FLAG(arrow, FLAG_FLYING);
  622.   SET_FLAG(arrow, FLAG_FLY_ON);
  623.   SET_FLAG(arrow, FLAG_WALK_ON);
  624.   insert_ob_in_map(arrow,head->map);
  625.   move_arrow(arrow);
  626.   return 1;
  627. }
  628.  
  629. int check_good_weapon(object *who, object *item) {
  630.   object *other_weap;
  631.   int prev_dam=who->stats.dam;
  632.   for(other_weap=who->inv;other_weap!=NULL;other_weap=other_weap->below)
  633.     if(other_weap->type==item->type&&QUERY_FLAG(other_weap,FLAG_APPLIED))
  634.       break;
  635.   if(other_weap==NULL) /* No other weapons */
  636.     return 1;
  637.   if (!apply(who,item)) {
  638.     LOG(llevMonster,"Can't wield %s(%d).\n",item->name,item->count);
  639.     return 0;
  640.   }
  641.   if(who->stats.dam < prev_dam && !QUERY_FLAG(other_weap,FLAG_FREED)) {
  642.     /* New weapon was worse.  (Note ^: Could have been freed by merging) */
  643.     if (!apply(who,other_weap))
  644.       LOG(llevMonster,"Can't rewield %s(%d).\n",item->name,item->count);
  645.     return 0;
  646.   }
  647.   return 1;
  648. }
  649.  
  650. int check_good_armour(object *who, object *item) {
  651.   object *other_armour;
  652.   int prev_ac = who->stats.ac;
  653.   for (other_armour = who->inv; other_armour != NULL;
  654.        other_armour = other_armour->below)
  655.     if (other_armour->type == item->type && QUERY_FLAG(other_armour,FLAG_APPLIED))
  656.       break;
  657.   if (other_armour == NULL) /* No other armour, use the new */
  658.     return 1;
  659.   if (!apply(who, item)) {
  660.     LOG(llevMonster, "Can't take off %s(%d).\n",item->name,item->count);
  661.     return 0;
  662.   }
  663.   if(who->stats.ac < prev_ac && !QUERY_FLAG(other_armour,FLAG_FREED)) {
  664.     /* New armour was worse. *Note ^: Could have been freed by merging) */
  665.     if (!apply(who, other_armour))
  666.       LOG(llevMonster,"Can't rewear %s(%d).\n", item->name, item->count);
  667.     return 0;
  668.   }
  669.   return 1;
  670. }
  671.  
  672. /*
  673.  * monster_check_pickup(): checks for items that monster can pick up.
  674.  *
  675.  * Vick's (vick@bern.docs.uu.se) fix 921030 for the sweeper blob.
  676.  * Each time the blob passes over some treasure, it will
  677.  * grab it a.s.a.p.
  678.  *
  679.  * Eneq(@csd.uu.se): This can now be defined in the archetypes, added code
  680.  * to handle this.
  681.  */
  682.  
  683. void monster_check_pickup(object *monster) {
  684.   object *tmp,*next;
  685. #if 0
  686.   object *outofdate;
  687. #endif
  688.   for(tmp=monster->below;tmp!=NULL;tmp=next) {
  689.     next=tmp->below;
  690.     if (monster_can_pick(monster,tmp)) {
  691.       remove_ob(tmp);
  692.       tmp = insert_ob_in_ob(tmp,monster);
  693.       (void) monster_check_apply(monster,tmp);
  694.     }
  695.   }
  696. }
  697.  
  698. /*
  699.  * monster_can_pick(): If the monster is interested in picking up
  700.  * the item, then return 0.  Otherwise 0.
  701.  * Instead of pick_up, flags for "greed", etc, should be used.
  702.  * I've already utilized flags for bows, wands, rings, etc, etc. -Frank.
  703.  */
  704.  
  705. int monster_can_pick(object *monster, object *item) {
  706.   int flag=0;
  707.   if(!can_pick(monster,item))
  708.     return 0;
  709.   if(QUERY_FLAG(item,FLAG_UNPAID))
  710.     return 0;
  711.   if (monster->pick_up&64)           /* All */
  712.     flag=1;
  713.   else switch(item->type) {
  714.   case MONEY:
  715.   case GEM:
  716.     flag=monster->pick_up&2;
  717.     break;
  718.   case FOOD:
  719.     flag=monster->pick_up&4;
  720.     break;
  721.   case WEAPON:
  722.     flag=(monster->pick_up&8)||QUERY_FLAG(monster,FLAG_USE_WEAPON);
  723.     break;
  724.   case ARMOUR:
  725.   case SHIELD:
  726.   case HELMET:
  727.     flag=(monster->pick_up&16)||QUERY_FLAG(monster,FLAG_USE_ARMOUR);
  728.     break;
  729.   case RING:
  730.     flag=QUERY_FLAG(monster,FLAG_USE_RING);
  731.     break;
  732.   case WAND:
  733.     flag=QUERY_FLAG(monster,FLAG_USE_WAND);
  734.     break;
  735.   case SPELLBOOK:
  736.     flag=(monster->arch!=NULL&&QUERY_FLAG((&monster->arch->clone),FLAG_CAST_SPELL));
  737.     break;
  738.   case BOW:
  739.   case ARROW:
  740.     flag=QUERY_FLAG(monster,FLAG_USE_BOW);
  741.     break;
  742.   }
  743.   if (((!(monster->pick_up&32))&&flag) || ((monster->pick_up&32)&&(!flag)))
  744.     return 1;
  745.   return 0;
  746. }
  747.  
  748. /*
  749.  * monster_apply_below():
  750.  * Vick's (vick@bern.docs.uu.se) @921107 -> If a monster who's
  751.  * eager to apply things, encounters something apply-able,
  752.  * then make him apply it
  753.  */
  754.  
  755. void monster_apply_below(object *monster) {
  756.   object *tmp, *next;
  757.  
  758.   for(tmp=monster->below;tmp!=NULL;tmp=next) {
  759.     next=tmp->below;
  760.     switch (tmp->type) {
  761.     case HANDLE:
  762.       if (monster->will_apply&1)
  763.         apply(monster,tmp);
  764.       break;
  765.     case TREASURE:
  766.       if (monster->will_apply&2)
  767.         apply(monster,tmp);
  768.       break;
  769.     case SCROLL:  /* Ideally, they should wait until they meet a player */
  770.       if (QUERY_FLAG(monster,FLAG_USE_SCROLL))
  771.         apply(monster,tmp); 
  772.       break;
  773.     }
  774.   }
  775. }
  776.  
  777. /*
  778.  * monster_check_apply() is meant to be called after an item is
  779.  * inserted in a monster.
  780.  * If an item becomes outdated (monster found a better item),
  781.  * a pointer to that object is returned, so it can be dropped.
  782.  * (so that other monsters can pick it up and use it)
  783.  */
  784.  
  785. void monster_check_apply(object *mon, object *item) {
  786.  
  787.   if(item->type==SPELLBOOK&&
  788.      mon->arch!=NULL&&(QUERY_FLAG((&mon->arch->clone),FLAG_CAST_SPELL))) {
  789.     SET_FLAG(mon, FLAG_CAST_SPELL);
  790.     return;
  791.   }
  792.   if(QUERY_FLAG(mon,FLAG_USE_BOW) && item->type==ARROW)
  793.   { /* Check for the right kind of bow */
  794.     object *bow;
  795.     for(bow=mon->inv;bow!=NULL;bow=bow->below)
  796.       if(bow->type==BOW && bow->race==item->race) {
  797.         SET_FLAG(mon, FLAG_READY_BOW);
  798.         LOG(llevMonster,"Found correct bow for arrows.\n");
  799.         if(!QUERY_FLAG(bow, FLAG_APPLIED))
  800.           apply(mon,bow);
  801.         break;
  802.       }
  803.   }
  804. /* Mol: (mol@meryl.csd.uu.se) If can_apply <number> is defined in the objects
  805.    archetype it can apply the object. See global.h for more info. */
  806.   if (can_apply(mon,item)) {
  807.     int flag=0;
  808.     if (mon->can_apply&64)         /* All */
  809.         flag=1;
  810.     else switch(item->type) {
  811.     case TREASURE:
  812.       flag=0;
  813.     break;
  814.     case POTION:
  815.       flag=mon->can_apply&2;
  816.       break;
  817.     case FOOD: /* Can a monster eat food ?  Yes! (it heals) */
  818.       flag=mon->can_apply&4;
  819.       break;
  820.     case WEAPON:
  821. /*
  822.  * Apply only if it's a better weapon than the used one.
  823.  * All "standard" monsters need to adjust their wc to use the can_apply on
  824.  * weapons.
  825.  */
  826.       flag=((mon->can_apply&8)||QUERY_FLAG(mon,FLAG_USE_WEAPON))&&
  827.             check_good_weapon(mon,item);
  828.       break;
  829.     case ARMOUR:
  830.     case HELMET:
  831.     case SHIELD:
  832.       flag=((mon->can_apply&16)||QUERY_FLAG(mon,FLAG_USE_ARMOUR))&&
  833.             check_good_armour(mon,item);
  834.       break;
  835.     case RING:
  836.       flag=QUERY_FLAG(mon,FLAG_USE_RING);
  837.       break;
  838.     case WAND:
  839.       flag=QUERY_FLAG(mon,FLAG_USE_WAND);
  840.       break;
  841.     case BOW:
  842.       flag=QUERY_FLAG(mon,FLAG_USE_BOW);
  843.     }
  844.     if (((!(mon->can_apply&32))&&flag) ||((mon->can_apply&32)&&(!flag))) {
  845.         /* &32 reverses behaviour. See global.h */
  846.         if(!QUERY_FLAG(item,FLAG_APPLIED))
  847.           apply(mon,item);
  848.         if (item->type==BOW&&present_in_ob(item->stats.maxsp,mon)!=NULL)
  849.       SET_FLAG(mon, FLAG_READY_BOW);
  850.     }
  851.     return;
  852. #if 0
  853.     if(!QUERY_FLAG(item,FLAG_APPLIED))
  854.       return item;
  855.     {
  856.       object *tmp;
  857.       for(tmp=mon->inv;tmp!=NULL;tmp=tmp->below)
  858.         if(tmp!=item&&tmp->type==item->type)
  859.           return tmp;
  860.     }
  861. #endif
  862.   }
  863.   return;
  864. }
  865.  
  866. void npc_call_help(object *op) {
  867.   int x,y;
  868.   object *npc;
  869.  
  870.   for(x = -3; x < 4; x++)
  871.     for(y = -3; y < 4; y++) {
  872.       if(out_of_map(op->map,op->x+x,op->y+y))
  873.         continue;
  874.       for(npc = get_map_ob(op->map,op->x+x,op->y+y);npc!=NULL;npc=npc->above)
  875.         if(QUERY_FLAG(npc, FLAG_ALIVE)&&QUERY_FLAG(npc, FLAG_UNAGGRESSIVE))
  876.           npc->enemy = op->enemy;
  877.     }
  878. }
  879.  
  880. int dist_att (int dir , object *ob, object *enemy, object *part) {
  881.   int dist;
  882.   if (can_hit(part,enemy))
  883.     return dir;
  884.   dist = distance (ob,enemy);
  885.   if (dist < 10)
  886.     return absdir(dir+4);
  887.   else if (dist>81) {
  888.     return dir;
  889.   }
  890.   return 0;
  891. }
  892.  
  893. int run_att (int dir, object *ob, object *enemy,object *part) {
  894.   if ((can_hit (part,enemy) && ob->move_status <20) || ob->move_status <20)
  895.   {
  896.     ob->move_status++;
  897.     return (dir);
  898.   }
  899.   else if (ob->move_status >20)
  900.     ob->move_status = 0;
  901.   return absdir (dir+4);
  902. }
  903.  
  904. int hitrun_att (int dir, object *ob,object *enemy) {
  905.   if (ob->move_status ++ < 25)  
  906.     return dir;
  907.   else if (ob->move_status <50) 
  908.     return absdir (dir+4); 
  909.   else 
  910.     ob->move_status = 0;
  911.   return absdir(dir+4);
  912. }
  913.  
  914. int wait_att (int dir, object *ob,object *enemy,object *part) {
  915.   int inrange = can_hit (part, enemy);
  916.       
  917.   if (ob->move_status || inrange)
  918.     ob->move_status++;
  919.  
  920.   if (ob->move_status == 0)
  921.     return 0;
  922.   else if (ob->move_status <10)
  923.     return dir;
  924.   else if (ob->move_status <15)
  925.     return absdir(dir+4);
  926.   ob->move_status = 0;
  927.   return 0;
  928. }
  929.  
  930. int disthit_att (int dir, object *ob, object *enemy, object *part) {
  931.   if (ob->stats.hp < (signed short)(((float)ob->run_away/(float)50*
  932.                      (float)ob->stats.maxhp)))
  933.     return dir;
  934.   return dist_att (dir,ob,enemy,part);
  935. }
  936.  
  937. int wait_att2 (int dir, object *ob,object *enemy,object *part) {
  938.   int dist = distance (ob,enemy);
  939.  
  940.   if ( dist < 9)
  941.     return absdir (dir+4);
  942.   return 0;
  943. }
  944.  
  945. void circ1_move (object *ob) {
  946.   static int circle [12] = {3,3,4,5,5,6,7,7,8,1,1,2};
  947.   if(++ob->move_status > 11)
  948.     ob->move_status = 0;
  949.   if (!(move_object(ob,circle[ob->move_status])))
  950.     (void) move_object(ob,RANDOM()%8+1);
  951. }
  952.  
  953. void circ2_move (object *ob) {
  954.   static int circle[20] = {3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,1,1,1,2,2};
  955.   if(++ob->move_status > 19)
  956.     ob->move_status = 0;
  957.   if(!(move_object(ob,circle[ob->move_status])))
  958.     (void) move_object(ob,RANDOM()%8+1);
  959. }
  960.  
  961. void pace_movev(object *ob) {
  962.   if (ob->move_status++ > 6)
  963.     ob->move_status = 0;
  964.   if (ob->move_status < 4)
  965.     (void) move_object (ob,5);
  966.   else
  967.     (void) move_object(ob,1);
  968. }
  969.  
  970. void pace_moveh (object *ob) {
  971.   if (ob->move_status++ > 6)
  972.     ob->move_status = 0;
  973.   if (ob->move_status < 4)
  974.     (void) move_object(ob,3);
  975.   else
  976.     (void) move_object(ob,7);
  977. }
  978.  
  979. void pace2_movev (object *ob) {
  980.   if (ob->move_status ++ > 16)
  981.     ob->move_status = 0;
  982.   if (ob->move_status <6)
  983.     (void) move_object (ob,5);
  984.   else if (ob->move_status < 8)
  985.     return;
  986.   else if (ob->move_status <13)
  987.     (void) move_object (ob,1);
  988.   else return;
  989. }       
  990.  
  991. void pace2_moveh (object *ob) {
  992.   if (ob->move_status ++ > 16)
  993.     ob->move_status = 0;
  994.   if (ob->move_status <6)
  995.     (void) move_object (ob,3);
  996.   else if (ob->move_status < 8)
  997.     return;
  998.   else if (ob->move_status <13)
  999.     (void) move_object (ob,7);
  1000.   else return;
  1001. }       
  1002.  
  1003. void rand_move (object *ob) {
  1004.   int i;
  1005.   if (ob->move_status <1 || ob->move_status >8 ||
  1006.       !(move_object(ob,ob->move_status|| ! (RANDOM()% 9))))
  1007.     for (i = 0; i < 5; i++)
  1008.       if (move_object(ob,ob->move_status = RANDOM()%8+1))
  1009.         return;
  1010. }
  1011.  
  1012. void check_earthwalls(object *op, int x, int y) {
  1013.   object *tmp;
  1014.   tmp = get_map_ob(op->map, x, y);
  1015.   if (tmp!= NULL)
  1016.     while(tmp->above != NULL)
  1017.       tmp=tmp->above;
  1018.   if (tmp!= NULL && tmp->type == EARTHWALL)
  1019.     hit_player(tmp,op->stats.dam,op,AT_PHYSICAL);
  1020. }
  1021.  
  1022. void check_doors(object *op, int x, int y) {
  1023.   object *tmp;
  1024.   tmp = get_map_ob(op->map, x, y);
  1025.   if (tmp!= NULL)
  1026.     while(tmp->above != NULL)
  1027.       tmp=tmp->above;
  1028.   if (tmp!= NULL && tmp->type == DOOR)
  1029.     hit_player(tmp,1000,op,AT_PHYSICAL);
  1030. }
  1031.  
  1032. /*
  1033.  * move_object() tries to move object op in the direction "dir".
  1034.  * If it fails (something blocks the passage), it returns 0,
  1035.  * otherwise 1.
  1036.  * This is an improvement from the previous move_ob(), which
  1037.  * removed and inserted objects even if they were unable to move.
  1038.  */
  1039.  
  1040. int move_object(object *op, int dir) {
  1041.   int newx = op->x+freearr_x[dir];
  1042.   int newy = op->y+freearr_y[dir];
  1043.   object *tmp;
  1044.   if(blocked_link(op, newx, newy)) /* Not all features from blocked_two yet */
  1045.     return 0;                      /* (Not efficient enough yet) */
  1046.   if(op->more != NULL && !move_object(op->more, dir))
  1047.     return 0;
  1048.   if(op->will_apply&4)
  1049.     check_earthwalls(op,newx,newy);
  1050.   if(op->will_apply&8)
  1051.     check_doors(op,newx,newy);
  1052.   if(op->head)
  1053.     return 1;
  1054.   remove_ob(op);
  1055.   for(tmp = op; tmp != NULL; tmp = tmp->more)
  1056.     tmp->x+=freearr_x[dir], tmp->y+=freearr_y[dir];
  1057.   insert_ob_in_map(op, op->map);
  1058.   return 1;
  1059. }
  1060.  
  1061. msglang *parse_message(char *msg) {
  1062.   msglang *msgs;
  1063.   int nrofmsgs, msgnr, i;
  1064.   char *cp, *line, *last;
  1065.   char *buf = strdup_local(msg);
  1066.  
  1067.   /* First find out how many messages there are.  A @ for each. */
  1068.   for (nrofmsgs = 0, cp = buf; *cp; cp++)
  1069.     if (*cp == '@')
  1070.       nrofmsgs++;
  1071.   if (!nrofmsgs)
  1072.     return NULL;
  1073.  
  1074.   msgs = (msglang *) malloc(sizeof(msglang));
  1075.   msgs->messages = (char **) malloc(sizeof(char *) * (nrofmsgs + 1));
  1076.   msgs->keywords = (char ***) malloc(sizeof(char **) * (nrofmsgs + 1));
  1077.   for(i=0; i<=nrofmsgs; i++) {
  1078.     msgs->messages[i] = NULL;
  1079.     msgs->keywords[i] = NULL;
  1080.   }
  1081.  
  1082.   for (last = NULL, cp = buf, msgnr = 0;*cp; cp++)
  1083.     if (*cp == '@') {
  1084.       int nrofkeywords, keywordnr;
  1085.       *cp = '\0'; cp++;
  1086.       if(last != NULL)
  1087.         msgs->messages[msgnr++] = strdup_local(last);
  1088.       if(strncmp(cp,"match",5)) {
  1089.         LOG(llevError,"Unsupported command in message.\n");
  1090.         free(buf);
  1091.         return NULL;
  1092.       }
  1093.       for(line = cp + 6, nrofkeywords = 0; *line != '\n' && *line; line++)
  1094.         if(*line == '|')
  1095.           nrofkeywords++;
  1096.       if(line > cp + 6)
  1097.         nrofkeywords++;
  1098.       if(nrofkeywords < 1) {
  1099.         LOG(llevError,"Too few keywords in message.\n");
  1100.         free(buf);
  1101.         free_messages(msgs);
  1102.         return NULL; 
  1103.       }
  1104.       msgs->keywords[msgnr] = (char **) malloc(sizeof(char **) * (nrofkeywords +1));
  1105.       msgs->keywords[msgnr][nrofkeywords] = NULL;
  1106.       last = cp + 6;
  1107.       cp = strchr(cp,'\n');
  1108.       if(cp != NULL)
  1109.         cp++;
  1110.       for(line = last, keywordnr = 0;line<cp && *line;line++)
  1111.         if(*line == '\n' || *line == '|') {
  1112.           *line = '\0';
  1113.           if (last != line)
  1114.             msgs->keywords[msgnr][keywordnr++] = strdup_local(last);
  1115.           last = line + 1;
  1116.         }
  1117.       last = cp;
  1118.     }
  1119.   if(last != NULL)
  1120.     msgs->messages[msgnr++] = strdup_local(last);
  1121.   free(buf);
  1122.   return msgs;
  1123. }
  1124.  
  1125. void free_messages(msglang *msgs) {
  1126.   int messages, keywords;
  1127.   for(messages = 0; msgs->messages[messages]; messages++) {
  1128.     if(msgs->keywords[messages])
  1129.       for(keywords = 0; msgs->keywords[messages][keywords]; keywords++)
  1130.         free(msgs->keywords[messages][keywords]);
  1131.     free(msgs->messages[messages]);
  1132.   }
  1133.   free(msgs->messages);
  1134.   free(msgs->keywords);
  1135. }
  1136.  
  1137. void dump_messages(msglang *msgs) {
  1138.   int messages, keywords;
  1139.   for(messages = 0; msgs->messages[messages]; messages++) {
  1140.     LOG(llevDebug, "@match ");
  1141.     for(keywords = 0; msgs->keywords[messages][keywords]; keywords++)
  1142.       LOG(llevDebug, "%s ",msgs->keywords[messages][keywords]);
  1143.     LOG(llevDebug, "\n%s\n",msgs->messages[messages]);
  1144.   }
  1145. }
  1146.  
  1147. void communicate(object *op, char *txt) {
  1148.   object *npc;
  1149.   int i;
  1150.   for(i = 0; i < 24; i++)
  1151.     if (!out_of_map(op->map, op->x+freearr_x[i], op->y+freearr_y[i]))
  1152.       for(npc = get_map_ob(op->map,op->x+freearr_x[i],op->y+freearr_y[i]);
  1153.           npc != NULL; npc = npc->above)
  1154.         if (npc->type == MAGIC_EAR)
  1155.           (void) talk_to_wall(npc, txt); /* Maybe exit after 1. success? */
  1156.         else
  1157.           if (talk_to_npc(npc,txt))
  1158.             return; /* Can be crowded */
  1159. }
  1160.  
  1161. int talk_to_npc(object *npc, char *txt) {
  1162.   msglang *msgs;
  1163.   int i,j;
  1164.  
  1165.   if(npc->msg == NULL || *npc->msg != '@')
  1166.     return 0;
  1167.   if((msgs = parse_message(npc->msg)) == NULL)
  1168.     return 0;
  1169. #if 0 /* Turn this on again when enhancing parse_message() */
  1170.   if(debug)
  1171.     dump_messages(msgs);
  1172. #endif
  1173.   for(i=0; msgs->messages[i]; i++)
  1174.     for(j=0; msgs->keywords[i][j]; j++)
  1175.       if(msgs->keywords[i][j][0] == '*' || re_cmp(txt,msgs->keywords[i][j])) {
  1176.         char buf[MAX_BUF];
  1177.         sprintf(buf,"The %s says:",query_name(npc));
  1178.     new_info_map(NDI_NAVY|NDI_UNIQUE, npc->map,buf);
  1179.     new_info_map(NDI_NAVY | NDI_UNIQUE, npc->map, msgs->messages[i]);
  1180.         free_messages(msgs);
  1181.         return 1;
  1182.       }
  1183.   free_messages(msgs);
  1184.   return 0;
  1185. }
  1186.  
  1187. int talk_to_wall(object *npc, char *txt) {
  1188.   msglang *msgs;
  1189.   int i,j;
  1190.  
  1191.   if(npc->msg == NULL || *npc->msg != '@')
  1192.     return 0;
  1193.   if((msgs = parse_message(npc->msg)) == NULL)
  1194.     return 0;
  1195.   if(debug)
  1196.     dump_messages(msgs);
  1197.   for(i=0; msgs->messages[i]; i++)
  1198.     for(j=0; msgs->keywords[i][j]; j++)
  1199.       if(msgs->keywords[i][j][0] == '*' || re_cmp(txt,msgs->keywords[i][j])) {
  1200.         if (msgs->messages[i] && *msgs->messages[i] != 0)
  1201.       new_info_map(NDI_NAVY | NDI_UNIQUE, npc->map,msgs->messages[i]);
  1202.         free_messages(msgs);
  1203.     use_trigger(npc);
  1204.         return 1;
  1205.       }
  1206.   free_messages(msgs);
  1207.   return 0;
  1208. }
  1209.